import operator
import sys

from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtWidgets import (QApplication, QWidget, QMainWindow, QSlider, QFileDialog, QMessageBox, QLabel, QVBoxLayout,
                             QPushButton, QLineEdit, QHBoxLayout)
from PyQt5.QtGui import (QPainter, QPen, QCursor, QPalette, QColor, QIntValidator)
from PyQt5.QtCore import Qt, pyqtSignal


class MyImageLabel(QLabel):
    undo_signal = pyqtSignal(bool)
    redo_signal = pyqtSignal(bool)
    unsaved_signal = pyqtSignal()
    edited_signal = pyqtSignal(bool)

    def __init__(self, para, color):
        super().__init__(para)

        # setMouseTracking设置为False，否则不按下鼠标时也会跟踪鼠标事件
        self.setMouseTracking(False)
        self.setStyleSheet("QMainWindow{background-color: white}")
        self.mode = None
        self.setPen()
        self.backgroundColor = Qt.white
        self.eraseSize = 5
        self.penColor = color
        self.penSize = 2
        self.saved = False
        self.filename = None
        '''
            要想将按住鼠标后移动的轨迹保留在窗体上
            需要一个列表来保存所有移动过的点
        '''
        self.pos_xy = []
        # self.del_xy = []

        self.undo_stack = []
        self.redo_stack = []

    def paintEvent(self, event):
        super(MyImageLabel, self).paintEvent(event)
        painter = QPainter()
        painter.begin(self)
        painter.setRenderHint(QPainter.Antialiasing)
        if len(self.pos_xy) > 1:
            point_start = self.pos_xy[0]
            for pos_tmp in self.pos_xy:
                point_end = pos_tmp

                if point_end[0:2] == (-1, -1):
                    point_start = (-1, -1)
                    continue
                if point_start[0:2] == (-1, -1):
                    point_start = point_end
                    continue

                # pen = QPen(Qt.black, 2, Qt.SolidLine)
                pen = QPen(point_start[2], point_start[3], Qt.SolidLine)
                painter.setPen(pen)
                painter.drawLine(point_start[0], point_start[1], point_end[0], point_end[1])
                point_start = point_end
        painter.end()

    def mousePressEvent(self, event):
        '''
            按住鼠标移动事件：将当前点添加到pos_xy列表中
            调用update()函数在这里相当于调用paintEvent()函数
            每次update()时，之前调用的paintEvent()留下的痕迹都会清空
        '''
        # 中间变量pos_tmp提取当前点
        self.undo_stack.append(self.pos_xy.copy())
        self.redo_stack.clear()
        if self.mode == "pen" or self.mode == "erase":
            self.undo_signal.emit(True)

            pos_tmp = (event.pos().x(), event.pos().y(), \
                       self.penColor[0] if self.mode == "pen" else self.backgroundColor, \
                       self.penSize if self.mode == "pen" else self.eraseSize)
            # pos_tmp添加到self.pos_xy中
            self.pos_xy.append(pos_tmp)


    def mouseMoveEvent(self, event):
        '''
            按住鼠标移动事件：将当前点添加到pos_xy列表中
            调用update()函数在这里相当于调用paintEvent()函数
            每次update()时，之前调用的paintEvent()留下的痕迹都会清空
        '''
        # 中间变量pos_tmp提取当前点
        if self.mode == "pen" or self.mode == "erase":
            pos_tmp = (event.pos().x(), event.pos().y(), \
                       self.penColor[0] if self.mode == "pen" else self.backgroundColor, \
                       self.penSize if self.mode == "pen" else self.eraseSize)
            # pos_tmp添加到self.pos_xy中, 补充空隙
            while (self.pos_xy[-1][0] - pos_tmp[0]) **2 + (self.pos_xy[-1][1] - pos_tmp[1]) **2 > 3 ** 2:
                factor = (9 / ((self.pos_xy[-1][0] - pos_tmp[0]) **2 + (self.pos_xy[-1][1] - pos_tmp[1]) **2)) ** 0.5
                x = int(self.pos_xy[-1][0] + (pos_tmp[0] - self.pos_xy[-1][0]) * factor)
                y = int(self.pos_xy[-1][1] + (pos_tmp[1] - self.pos_xy[-1][1]) * factor)
                self.pos_xy.append((x, y, self.penColor[0] if self.mode == "pen" else self.backgroundColor,
                                    self.penSize if self.mode == "pen" else self.eraseSize))
            self.pos_xy.append(pos_tmp)
        elif self.mode == "erase_paint":
            pos_tmp = (event.pos().x(), event.pos().y())
            # 将橡皮擦范围内的点赋值为（-1， -1）
            for i in range(self.pos_xy.__len__()):
                if (self.pos_xy[i][0] - pos_tmp[0]) ** 2 + (self.pos_xy[i][1] - pos_tmp[1]) ** 2 < self.eraseSize ** 2:
                    self.pos_xy[i] = (-1, -1)
            imin = -1
            # 缩短数组，合并相邻的（-1，-1）
            for i in range(self.pos_xy.__len__()):
                if i < self.pos_xy.__len__() and operator.eq(self.pos_xy[i], (-1, -1)) and imin == -1:
                    imin = i
                elif i < self.pos_xy.__len__() and imin != -1 and not operator.eq(self.pos_xy[i], (-1, -1)):
                    if i - 1 > imin != -1:
                        del self.pos_xy[imin + 1:i]
                    imin = -1
        self.edited_signal.emit(True)
        self.update()

    def mouseReleaseEvent(self, event):
        '''
            重写鼠标按住后松开的事件
            在每次松开后向pos_xy列表中添加一个断点(-1, -1)
            然后在绘画时判断一下是不是断点就行了
            是断点的话就跳过去，不与之前的连续
        '''
        if self.mode == "pen" or self.mode == "erase":
            if len(self.pos_xy) > 1 and self.pos_xy[-2][0:2] == (-1, -1):
                self.pos_xy.append((self.pos_xy[-1][0], self.pos_xy[-1][1]))
            pos_test = (-1, -1,
                        self.penColor[0] if self.mode == "pen" else self.backgroundColor,
                        self.penSize if self.mode == "pen" else self.eraseSize)
            self.pos_xy.append(pos_test)
        self.update()
        self.unsaved_signal.emit()
        self.edited_signal.emit(True)

    def closeEvent(self, event):
        self.closed.emit()
        while QApplication.overrideCursor() is not None:
            QApplication.restoreOverrideCursor()

    def sizeAdd(self):
        if self.mode == "pen":
            self.penSize += 1
        elif self.mode == "erase" or self.mode == "erase_paint":
            self.eraseSize += 2

    def sizeDec(self):
        if self.mode == "pen":
            self.penSize -= 1
        elif self.mode == "erase" or self.mode == "erase_paint":
            self.eraseSize -= 2

    def setErase(self):
        self.mode = "erase"
        QApplication.setOverrideCursor(QCursor(QtGui.QPixmap('./ui/eraser.png')))

    def setErasePaint(self):
        self.mode = "erase_paint"
        QApplication.setOverrideCursor(QCursor(QtGui.QPixmap('./ui/eraser2.png')))

    def setPen(self):
        self.mode = "pen"
        QApplication.setOverrideCursor(QCursor(QtGui.QPixmap('./ui/pencil.png')))

    def undo(self):
        if len(self.undo_stack) != 0:
            self.redo_stack.append(self.pos_xy.copy())
            self.pos_xy = self.undo_stack.pop()
            self.redo_signal.emit(True)
        if len(self.undo_stack) == 0:
            self.undo_stack = [[]]
            self.undo_signal.emit(False)
            self.edited_signal.emit(False)
        self.update()

    def redo(self):
        if len(self.redo_stack) == 0:
            self.undo_stack = [[]]
            self.redo_signal.emit(False)
            return
        self.undo_stack.append(self.pos_xy.copy())
        self.pos_xy = self.redo_stack.pop()
        self.undo_signal.emit(True)
        self.update()

    # def undo(self):
    #     if len(self.pos_xy) != 0:
    #         for i in self.pos_xy[-2::-1]:
    #             self.del_xy.append(self.pos_xy.pop())
    #             if i[0:2] == (-1, -1):
    #                 break
    #         if len(self.pos_xy) == 1:
    #             self.pos_xy.pop()
    #         self.update()
    #         self.redo_signal.emit(True)
    #     if len(self.pos_xy) == 0:
    #         self.undo_signal.emit(False)
    #         self.edited_signal.emit(False)
    #
    # def redo(self):
    #     if len(self.del_xy) == 0:
    #         self.redo_signal.emit(False)
    #         return
    #     while self.del_xy[-1][0: 2] != (-1, -1):
    #         self.pos_xy.append(self.del_xy.pop())
    #     self.pos_xy.append(self.del_xy.pop())
    #     self.update()
    #     self.undo_signal.emit(True)
